import zmq
import threading
import time
import netifaces as ni #external
import cPickle
import json
import zlib
import sys
import signal
import logging
sys.path.append("./")
from random import choice
from utils import *
import multiprocessing

interrupted = False

def signal_handler(signum, frame):
    global interrupted
    interrupted = True
signal.signal(signal.SIGINT, signal_handler)
class MSG(object):
    """docstring for MSG"""
    def __init__(self):
        pass
    def msg_reg_new(self,mid):
        msg={}
        msg["id"]=mid
        msg["type"]="guard_new"
        msg["body"]=get_host_info()
        return zlib.compress(json.dumps(msg),zlib.Z_BEST_SPEED)

    def msg_req_in(self,mid,fid):
        msg={}
        msg["id"]=mid
        msg["from_id"]=fid
        msg["type"]="req_in"
        msg["body"]=get_host_info()
        return zlib.compress(json.dumps(msg),zlib.Z_BEST_SPEED)
 
def serverworker(context,no):
	worker = ServerWorker(context)
	worker.start_w()
	pass      

class PolicyGuard():
    """docstring for PolicyGuard"""
    def __init__(self):
        self.id="None"
        self.context = zmq.Context()
        self.app_router = self.context.socket(zmq.ROUTER)
        self.app_dealer = self.context.socket(zmq.DEALER)
        self.ctr_router = self.context.socket(zmq.DEALER)
        self.ctr_dealer = self.context.socket(zmq.DEALER)
        self.app_list={}
        self.sockets=[]
        self.worker_no=10
        self.workers=[]
        self.st_time=0
        self.ed_time=0
        self.total_count=0
        self.miss_count=0
        
        self.msg=MSG()
        self.poller = zmq.Poller()
        self.bind()
        self.register_clr()
        self.register_poll()
        #self.init_worker()
        #self.start()
        
        #self.clean()


    def bind(self):
        self.app_router.bind('ipc://guard_app.ipc')
        self.app_dealer.bind('ipc://guard_worker.ipc')
        self.ctr_dealer.bind('ipc://guard_ctr.ipc')

    def clean(self):
        self.app_router.close()
        self.app_dealer.close()
        self.ctr_dealer.close()
        self.ctr_router.close()
        self.context.term()
    
    def register_poll(self):
        self.poller.register(self.app_router, zmq.POLLIN)
        self.poller.register(self.app_dealer,  zmq.POLLIN)
        self.poller.register(self.ctr_router,  zmq.POLLIN)
        self.poller.register(self.ctr_dealer,  zmq.POLLIN)
        

    def register_clr(self):
        self.ctr_router.connect('tcp://localhost:5555')
        self.ctr_router.send(self.msg.msg_reg_new(self.id))
        while True:
            print "send"
            msg = self.ctr_router.recv()
            msg=eval(msg)
            if msg["type"]=="control_reg_req":
                self.id=msg["id"]
                print msg
                self.ctr_router.close()
                self.ctr_router = self.context.socket(zmq.DEALER)
                self.ctr_router.setsockopt(zmq.IDENTITY, self.id)
                self.ctr_router.connect('tcp://localhost:5555')
                break

    def init_worker(self,func):      
		p=multiprocessing.Process(target=func, args=(self.context,1))
		self.workers.append(p)
		p.daemon = True
		p.start()

    def finish_worker(self):
    	for t  in self.workers:
			t.join()
		
    
    def start_work(self):
        self.st_time=time.time()
        while True:
            if interrupted:
                print "W: interrupt received, killing server"
                
                print "time usage:",self.ed_time,self.st_time,self.ed_time-self.st_time
                print "hit_count:",self.total_count-self.miss_count
                print "miss_count:",self.miss_count
                print "total count:",self.total_count
                print "rate:",float(self.total_count)/float(self.ed_time-self.st_time)
                break
            sockets = dict(self.poller.poll(0))
            if self.app_router in sockets:
                if sockets[self.app_router] == zmq.POLLIN:
                    _id = self.app_router.recv()
                    msg = self.app_router.recv()
                    self.total_count+=1
                    print self.total_count
                    if self.total_count==100000:
                        self.ed_time=time.time()
                        print self.ed_time-self.st_time
                        sys.exit()
                    print 'guard received msg: %s from app %s' % (msg, _id)

                    """
                    app_registration()
                    """
                    self.app_dealer.send(_id, zmq.SNDMORE)
                    self.app_dealer.send(msg)
            if self.app_dealer in sockets:
                if sockets[self.app_dealer] == zmq.POLLIN:
                    _id = self.app_dealer.recv()
                    msg = self.app_dealer.recv()

                    self.app_router.send(_id, zmq.SNDMORE)
                    self.app_router.send(msg)

            if self.ctr_dealer in sockets:
                if sockets[self.ctr_dealer] == zmq.POLLIN:
                    _id = self.ctr_dealer.recv()
                    msg = self.ctr_dealer.recv()
                    #print 'guard dont know what to do for the request from %s' % (_id)
                    self.miss_count+=1
                    #self.ctr_router.send(_id, zmq.SNDMORE)
                    self.ctr_router.send(self.msg.msg_req_in(self.id,_id))
 

            if self.ctr_router in sockets:
                if sockets[self.ctr_router] == zmq.POLLIN:
                    msg = self.ctr_router.recv()
                    msg=eval(msg)
                    #print msg["type"]
                    if msg["type"]=="test":
                        #print msg
                        pass

                    if msg["type"]=="control_rep":
                        #print msg["body"]
                        _id=msg["from_id"]
                        self.app_router.send(_id, zmq.SNDMORE)
                        self.app_router.send("ok, block it")

                    #backend.send(_id, zmq.SNDMORE)
                    #backend.send(msg)
        pass

logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S",level=logging.INFO, filename='test.log',filemode='a') 


class ServerWorker():
    """ServerWorker"""
    def __init__(self, context):
        self.context = context
        print self.context

    def start_w(self):
        worker = self.context.socket(zmq.DEALER)
        worker.RCVTIMEO=1
        worker.connect('ipc://guard_worker.ipc')

        err_dealer = self.context.socket(zmq.DEALER)
        err_dealer.connect('ipc://guard_ctr.ipc')

        print 'worker started'
        while True:
            #print time.time()
            try:
            	_id = worker.recv()
            	msg = worker.recv()
            except:
            	continue
            print 'worker received %s from %s' % (msg, _id)
            #logging.info("get message: %s", msg)
            rep = str(time.time())[0:10]
            if int(rep)%5==0:
                err_dealer.send(_id,zmq.SNDMORE)
                err_dealer.send(msg)
            else:
                worker.send(_id, zmq.SNDMORE)
                worker.send(rep)

            del msg
            

        worker.close()

if __name__ == '__main__':
    guard = PolicyGuard()
    st_time=time.time()
    for i in xrange(guard.worker_no):
    	guard.init_worker(serverworker)
    guard.start_work()
    guard.finish_worker()
    ed_time=time.time()
    print "sys time usage",ed_time-st_time